/*!
 * mobileSelect.js
 * (c) 2017-present onlyhom
 * Released under the MIT License.
 */

(function () {
	function getClass(dom, string) {
		return dom.getElementsByClassName(string);
	}
	//构造器
	function MobileSelect(config) {
		this.mobileSelect;
		this.wheelsData = config.wheels;
		this.jsonType = false;
		this.cascadeJsonData = [];
		this.displayJson = [];
		this.cascade = false;
		this.startY;
		this.moveEndY;
		this.moveY;
		this.oldMoveY;
		this.offset = 0;
		this.offsetSum = 0;
		this.oversizeBorder;
		this.curDistance = [];
		this.clickStatus = false;
		this.isPC = true;
		this.init(config);
	}
	MobileSelect.prototype = {
		constructor: MobileSelect,
		init: function (config) {
			var _this = this;
			_this.keyMap = config.keyMap ? config.keyMap : { id: 'id', value: 'value', childs: 'childs' };
			_this.checkDataType();
			_this.renderWheels(_this.wheelsData, config.cancelBtnText, config.ensureBtnText);
			_this.trigger = document.querySelector(config.trigger);
			if (!_this.trigger) {
				console.error('mobileSelect has been successfully installed, but no trigger found on your page.');
				return false;
			}
			_this.wheel = getClass(_this.mobileSelect, 'wheel');
			_this.slider = getClass(_this.mobileSelect, 'selectContainer');
			_this.wheels = _this.mobileSelect.querySelector('.wheels');
			_this.liHeight = _this.mobileSelect.querySelector('li').offsetHeight;
			_this.ensureBtn = _this.mobileSelect.querySelector('.ensure');
			_this.cancelBtn = _this.mobileSelect.querySelector('.cancel');
			_this.grayLayer = _this.mobileSelect.querySelector('.grayLayer');
			_this.popUp = _this.mobileSelect.querySelector('.content');
			_this.callback = config.callback ? config.callback : function () { };
			_this.transitionEnd = config.transitionEnd ? config.transitionEnd : function () { };
			_this.initPosition = config.position ? config.position : [];
			_this.titleText = config.title ? config.title : '';
			_this.connector = config.connector ? config.connector : ' ';
			_this.trigger.style.cursor = 'pointer';
			_this.setStyle(config);
			_this.setTitle(_this.titleText);
			_this.checkIsPC();
			_this.checkCascade();
			if (_this.cascade) {
				_this.initCascade();
			}
			//定位 初始位置
			if (_this.initPosition.length < _this.slider.length) {
				var diff = _this.slider.length - _this.initPosition.length;
				for (var i = 0; i < diff; i++) {
					_this.initPosition.push(0);
				}
			}

			_this.setCurDistance(_this.initPosition);
			_this.addListenerAll();

			//按钮监听
			_this.cancelBtn.addEventListener('click', function () {
				_this.mobileSelect.classList.remove('mobileSelect-show');
			});

			_this.ensureBtn.addEventListener('click', function () {
				_this.mobileSelect.classList.remove('mobileSelect-show');
				var tempValue = '';
				for (var i = 0; i < _this.wheel.length; i++) {
					i == _this.wheel.length - 1 ? tempValue += _this.getInnerHtml(i) : tempValue += _this.getInnerHtml(i) + _this.connector;
				}
				_this.trigger.innerHTML = tempValue;
				_this.callback(_this.getIndexArr(), _this.getValue());
			});

			_this.trigger.addEventListener('click', function () {
				_this.mobileSelect.classList.add('mobileSelect-show');
			});
			_this.grayLayer.addEventListener('click', function () {
				_this.mobileSelect.classList.remove('mobileSelect-show');
			});
			_this.popUp.addEventListener('click', function () {
				event.stopPropagation();
			});

			_this.fixRowStyle(); //修正列数
		},

		setTitle: function (string) {
			var _this = this;
			_this.titleText = string;
			_this.mobileSelect.querySelector('.title').innerHTML = _this.titleText;
		},

		setStyle: function (config) {
			var _this = this;
			if (config.ensureBtnColor) {
				_this.ensureBtn.style.color = config.ensureBtnColor;
			}
			if (config.cancelBtnColor) {
				_this.cancelBtn.style.color = config.cancelBtnColor;
			}
			if (config.titleColor) {
				_this.title = _this.mobileSelect.querySelector('.title');
				_this.title.style.color = config.titleColor;
			}
			if (config.textColor) {
				_this.panel = _this.mobileSelect.querySelector('.panel');
				_this.panel.style.color = config.textColor;
			}
			if (config.titleBgColor) {
				_this.btnBar = _this.mobileSelect.querySelector('.btnBar');
				_this.btnBar.style.backgroundColor = config.titleBgColor;
			}
			if (config.bgColor) {
				_this.panel = _this.mobileSelect.querySelector('.panel');
				_this.shadowMask = _this.mobileSelect.querySelector('.shadowMask');
				_this.panel.style.backgroundColor = config.bgColor;
				_this.shadowMask.style.background = 'linear-gradient(to bottom, ' + config.bgColor + ', rgba(255, 255, 255, 0), ' + config.bgColor + ')';
			}
		},

		checkIsPC: function () {
			var _this = this;
			var sUserAgent = navigator.userAgent.toLowerCase();
			var bIsIpad = sUserAgent.match(/ipad/i) == "ipad";
			var bIsIphoneOs = sUserAgent.match(/iphone os/i) == "iphone os";
			var bIsMidp = sUserAgent.match(/midp/i) == "midp";
			var bIsUc7 = sUserAgent.match(/rv:1.2.3.4/i) == "rv:1.2.3.4";
			var bIsUc = sUserAgent.match(/ucweb/i) == "ucweb";
			var bIsAndroid = sUserAgent.match(/android/i) == "android";
			var bIsCE = sUserAgent.match(/windows ce/i) == "windows ce";
			var bIsWM = sUserAgent.match(/windows mobile/i) == "windows mobile";
			if ((bIsIphoneOs || bIsMidp || bIsUc7 || bIsUc || bIsAndroid || bIsCE || bIsWM)) {
				_this.isPC = false;
			}
		},

		show: function () {
			this.mobileSelect.classList.add('mobileSelect-show');
		},

		renderWheels: function (wheelsData, cancelBtnText, ensureBtnText) {
			var _this = this;
			var cancelText = cancelBtnText ? cancelBtnText : '取消';
			var ensureText = ensureBtnText ? ensureBtnText : '确认';
			_this.mobileSelect = document.createElement("div");
			_this.mobileSelect.className = "mobileSelect";
			_this.mobileSelect.innerHTML =
				'<div class="grayLayer"></div>' +
				'<div class="content">' +

				'<div class="panel">' +
				'<div class="fixWidth">' +
				'<div class="wheels">' +
				'</div>' +
				'<div class="selectLine"></div>' +
				'<div class="shadowMask"></div>' +
				'</div>' +
				'</div>' +
				'<div class="btnBar">' +
				'<div class="fixWidth">' +
				'<div class="cancel">' + cancelText + '</div>' +
				'<div class="title"></div>' +
				'<div class="ensure">' + ensureText + '</div>' +
				'</div>' +
				'</div>' +
				'</div>';
			document.body.appendChild(_this.mobileSelect);

			//根据数据长度来渲染

			var tempHTML = '';
			for (var i = 0; i < wheelsData.length; i++) {
				//列
				tempHTML += '<div class="wheel"><ul class="selectContainer">';
				if (_this.jsonType) {
					for (var j = 0; j < wheelsData[i].data.length; j++) {
						//行
						tempHTML += '<li data-id="' + wheelsData[i].data[j][_this.keyMap.id] + '">' + wheelsData[i].data[j][_this.keyMap.value] + '</li>';
					}
				} else {
					for (var j = 0; j < wheelsData[i].data.length; j++) {
						//行
						tempHTML += '<li>' + wheelsData[i].data[j] + '</li>';
					}
				}
				tempHTML += '</ul></div>';
			}
			_this.mobileSelect.querySelector('.wheels').innerHTML = tempHTML;
		},

		addListenerAll: function () {
			var _this = this;
			for (var i = 0; i < _this.slider.length; i++) {
				//手势监听
				(function (i) {
					_this.addListenerWheel(_this.wheel[i], i);
					_this.addListenerLi(i);
				})(i);
			}
		},

		addListenerWheel: function (theWheel, index) {
			var _this = this;
			theWheel.addEventListener('touchstart', function () {
				_this.touch(event, this.firstChild, index);
			}, false);
			theWheel.addEventListener('touchend', function () {
				_this.touch(event, this.firstChild, index);
			}, false);
			theWheel.addEventListener('touchmove', function () {
				_this.touch(event, this.firstChild, index);
			}, false);

			if (_this.isPC) {
				//如果是PC端则再增加拖拽监听 方便调试
				theWheel.addEventListener('mousedown', function () {
					_this.dragClick(event, this.firstChild, index);
				}, false);
				theWheel.addEventListener('mousemove', function () {
					_this.dragClick(event, this.firstChild, index);
				}, false);
				theWheel.addEventListener('mouseup', function () {
					_this.dragClick(event, this.firstChild, index);
				}, true);
			}
		},

		addListenerLi: function (sliderIndex) {
			var _this = this;
			var curWheelLi = _this.slider[sliderIndex].getElementsByTagName('li');
			for (var j = 0; j < curWheelLi.length; j++) {
				(function (j) {
					curWheelLi[j].addEventListener('click', function () {
						_this.singleClick(this, j, sliderIndex);
					}, false);
				})(j);
			}
		},

		checkDataType: function () {
			var _this = this;
			if (typeof (_this.wheelsData[0].data[0]) == 'object') {
				_this.jsonType = true;
			}
		},

		checkCascade: function () {
			var _this = this;
			if (_this.jsonType) {
				var node = _this.wheelsData[0].data;
				for (var i = 0; i < node.length; i++) {
					if (_this.keyMap.childs in node[i] && node[i][_this.keyMap.childs].length > 0) {
						_this.cascade = true;
						_this.cascadeJsonData = _this.wheelsData[0].data;
						break;
					}
				}
			} else {
				_this.cascade = false;
			}
		},

		generateArrData: function (targetArr) {
			var tempArr = [];
			var keyMap_id = this.keyMap.id;
			var keyMap_value = this.keyMap.value;
			for (var i = 0; i < targetArr.length; i++) {
				var tempObj = {};
				tempObj[keyMap_id] = targetArr[i][this.keyMap.id];
				tempObj[keyMap_value] = targetArr[i][this.keyMap.value];
				tempArr.push(tempObj);
			}
			return tempArr;
		},

		initCascade: function () {
			var _this = this;
			_this.displayJson.push(_this.generateArrData(_this.cascadeJsonData));
			if (_this.initPosition.length > 0) {
				_this.initDeepCount = 0;
				_this.initCheckArrDeep(_this.cascadeJsonData[_this.initPosition[0]]);
			} else {
				_this.checkArrDeep(_this.cascadeJsonData[0]);
			}
			_this.reRenderWheels();
		},

		initCheckArrDeep: function (parent) {
			var _this = this;
			if (parent) {
				if (_this.keyMap.childs in parent && parent[_this.keyMap.childs].length > 0) {
					_this.displayJson.push(_this.generateArrData(parent[_this.keyMap.childs]));
					_this.initDeepCount++;
					var nextNode = parent[_this.keyMap.childs][_this.initPosition[_this.initDeepCount]];
					if (nextNode) {
						_this.initCheckArrDeep(nextNode);
					} else {
						_this.checkArrDeep(parent[_this.keyMap.childs][0]);
					}
				}
			}
		},

		checkArrDeep: function (parent) {
			//检测子节点深度  修改 displayJson
			var _this = this;
			if (parent) {
				if (_this.keyMap.childs in parent && parent[_this.keyMap.childs].length > 0) {
					_this.displayJson.push(_this.generateArrData(parent[_this.keyMap.childs])); //生成子节点数组
					_this.checkArrDeep(parent[_this.keyMap.childs][0]);//检测下一个子节点
				}
			}
		},

		checkRange: function (index, posIndexArr) {
			var _this = this;
			var deleteNum = _this.displayJson.length - 1 - index;
			for (var i = 0; i < deleteNum; i++) {
				_this.displayJson.pop(); //修改 displayJson
			}
			var resultNode;
			for (var i = 0; i <= index; i++) {
				if (i == 0)
					resultNode = _this.cascadeJsonData[posIndexArr[0]];
				else {
					resultNode = resultNode[_this.keyMap.childs][posIndexArr[i]];
				}
			}
			_this.checkArrDeep(resultNode);
			//console.log(_this.displayJson);
			_this.reRenderWheels();
			_this.fixRowStyle();
			_this.setCurDistance(_this.resetPostion(index, posIndexArr));
		},

		resetPostion: function (index, posIndexArr) {
			var _this = this;
			var tempPosArr = posIndexArr;
			var tempCount;
			if (_this.slider.length > posIndexArr.length) {
				tempCount = _this.slider.length - posIndexArr.length;
				for (var i = 0; i < tempCount; i++) {
					tempPosArr.push(0);
				}
			} else if (_this.slider.length < posIndexArr.length) {
				tempCount = posIndexArr.length - _this.slider.length;
				for (var i = 0; i < tempCount; i++) {
					tempPosArr.pop();
				}
			}
			for (var i = index + 1; i < tempPosArr.length; i++) {
				tempPosArr[i] = 0;
			}
			return tempPosArr;
		},

		reRenderWheels: function () {
			var _this = this;
			//删除多余的wheel
			if (_this.wheel.length > _this.displayJson.length) {
				var count = _this.wheel.length - _this.displayJson.length;
				for (var i = 0; i < count; i++) {
					_this.wheels.removeChild(_this.wheel[_this.wheel.length - 1]);
				}
			}
			for (var i = 0; i < _this.displayJson.length; i++) {
				//列
				(function (i) {
					var tempHTML = '';
					if (_this.wheel[i]) {
						//console.log('插入Li');
						for (var j = 0; j < _this.displayJson[i].length; j++) {
							//行
							tempHTML += '<li data-id="' + _this.displayJson[i][j][_this.keyMap.id] + '">' + _this.displayJson[i][j][_this.keyMap.value] + '</li>';
						}
						_this.slider[i].innerHTML = tempHTML;

					} else {
						var tempWheel = document.createElement("div");
						tempWheel.className = "wheel";
						tempHTML = '<ul class="selectContainer">';
						for (var j = 0; j < _this.displayJson[i].length; j++) {
							//行
							tempHTML += '<li data-id="' + _this.displayJson[i][j][_this.keyMap.id] + '">' + _this.displayJson[i][j][_this.keyMap.value] + '</li>';
						}
						tempHTML += '</ul>';
						tempWheel.innerHTML = tempHTML;

						_this.addListenerWheel(tempWheel, i);
						_this.wheels.appendChild(tempWheel);
					}
					_this.addListenerLi(i);
				})(i);
			}
		},

		updateWheels: function (data) {
			var _this = this;
			if (_this.cascade) {
				_this.cascadeJsonData = data;
				_this.displayJson = [];
				_this.initCascade();
				if (_this.initPosition.length < _this.slider.length) {
					var diff = _this.slider.length - _this.initPosition.length;
					for (var i = 0; i < diff; i++) {
						_this.initPosition.push(0);
					}
				}
				_this.setCurDistance(_this.initPosition);
				_this.fixRowStyle();
			}
		},

		updateWheel: function (sliderIndex, data) {
			var _this = this;
			var tempHTML = '';
			if (_this.cascade) {
				console.error('级联格式不支持updateWheel(),请使用updateWheels()更新整个数据源');
				return false;
			}
			else if (_this.jsonType) {
				for (var j = 0; j < data.length; j++) {
					tempHTML += '<li data-id="' + data[j][_this.keyMap.id] + '">' + data[j][_this.keyMap.value] + '</li>';
				}
				_this.wheelsData[sliderIndex] = { data: data };
			} else {
				for (var j = 0; j < data.length; j++) {
					tempHTML += '<li>' + data[j] + '</li>';
				}
				_this.wheelsData[sliderIndex] = data;
			}
			_this.slider[sliderIndex].innerHTML = tempHTML;
			_this.addListenerLi(sliderIndex);
		},

		fixRowStyle: function () {
			var _this = this;
			var width = (100 / _this.wheel.length).toFixed(2);
			for (var i = 0; i < _this.wheel.length; i++) {
				_this.wheel[i].style.width = width + '%';
			}
		},

		getIndex: function (distance) {
			return Math.round((2 * this.liHeight - distance) / this.liHeight);
		},

		getIndexArr: function () {
			var _this = this;
			var temp = [];
			for (var i = 0; i < _this.curDistance.length; i++) {
				temp.push(_this.getIndex(_this.curDistance[i]));
			}
			return temp;
		},

		getValue: function () {
			var _this = this;
			var temp = [];
			var positionArr = _this.getIndexArr();
			if (_this.cascade) {
				for (var i = 0; i < _this.wheel.length; i++) {
					temp.push(_this.displayJson[i][positionArr[i]]);
				}
			}
			else if (_this.jsonType) {
				for (var i = 0; i < _this.curDistance.length; i++) {
					temp.push(_this.wheelsData[i].data[_this.getIndex(_this.curDistance[i])]);
				}
			} else {
				for (var i = 0; i < _this.curDistance.length; i++) {
					temp.push(_this.getInnerHtml(i));
				}
			}
			return temp;
		},

		calcDistance: function (index) {
			return 2 * this.liHeight - index * this.liHeight;
		},

		setCurDistance: function (indexArr) {
			var _this = this;
			var temp = [];
			for (var i = 0; i < _this.slider.length; i++) {
				temp.push(_this.calcDistance(indexArr[i]));
				_this.movePosition(_this.slider[i], temp[i]);
			}
			_this.curDistance = temp;
		},

		fixPosition: function (distance) {
			return -(this.getIndex(distance) - 2) * this.liHeight;
		},

		movePosition: function (theSlider, distance) {
			theSlider.style.webkitTransform = 'translate3d(0,' + distance + 'px, 0)';
			theSlider.style.transform = 'translate3d(0,' + distance + 'px, 0)';
		},

		locatePostion: function (index, posIndex) {
			this.curDistance[index] = this.calcDistance(posIndex);
			this.movePosition(this.slider[index], this.curDistance[index]);
		},

		updateCurDistance: function (theSlider, index) {
			this.curDistance[index] = parseInt(theSlider.style.transform.split(',')[1]);
		},

		getDistance: function (theSlider) {
			return parseInt(theSlider.style.transform.split(',')[1]);
		},

		getInnerHtml: function (sliderIndex) {
			var _this = this;
			var index = _this.getIndex(_this.curDistance[sliderIndex]);
			return _this.slider[sliderIndex].getElementsByTagName('li')[index].innerHTML;
		},

		touch: function (event, theSlider, index) {
			var _this = this;
			event = event || window.event;
			switch (event.type) {
				case "touchstart":
					_this.startY = event.touches[0].clientY;
					_this.oldMoveY = _this.startY;
					break;

				case "touchend":

					_this.moveEndY = event.changedTouches[0].clientY;
					_this.offsetSum = _this.moveEndY - _this.startY;

					//修正位置
					_this.updateCurDistance(theSlider, index);
					_this.curDistance[index] = _this.fixPosition(_this.curDistance[index]);
					_this.movePosition(theSlider, _this.curDistance[index]);
					_this.oversizeBorder = -(theSlider.getElementsByTagName('li').length - 3) * _this.liHeight;


					//反弹
					if (_this.curDistance[index] + _this.offsetSum > 2 * _this.liHeight) {
						_this.curDistance[index] = 2 * _this.liHeight;
						setTimeout(function () {
							_this.movePosition(theSlider, _this.curDistance[index]);
						}, 100);

					} else if (_this.curDistance[index] + _this.offsetSum < _this.oversizeBorder) {
						_this.curDistance[index] = _this.oversizeBorder;
						setTimeout(function () {
							_this.movePosition(theSlider, _this.curDistance[index]);
						}, 100);
					}


					_this.transitionEnd(_this.getIndexArr(), _this.getValue());

					if (_this.cascade) {
						var tempPosArr = _this.getIndexArr();
						tempPosArr[index] = _this.getIndex(_this.curDistance[index]);
						_this.checkRange(index, tempPosArr);
					}

					break;

				case "touchmove":
					event.preventDefault();
					_this.moveY = event.touches[0].clientY;
					_this.offset = _this.moveY - _this.oldMoveY;

					_this.updateCurDistance(theSlider, index);
					_this.curDistance[index] = _this.curDistance[index] + _this.offset;
					_this.movePosition(theSlider, _this.curDistance[index]);
					_this.oldMoveY = _this.moveY;
					break;
			}
		},

		dragClick: function (event, theSlider, index) {
			var _this = this;
			event = event || window.event;
			switch (event.type) {
				case "mousedown":
					_this.startY = event.clientY;
					_this.oldMoveY = _this.startY;
					_this.clickStatus = true;
					break;

				case "mouseup":

					_this.moveEndY = event.clientY;
					_this.offsetSum = _this.moveEndY - _this.startY;

					//修正位置
					_this.updateCurDistance(theSlider, index);
					_this.curDistance[index] = _this.fixPosition(_this.curDistance[index]);
					_this.movePosition(theSlider, _this.curDistance[index]);
					_this.oversizeBorder = -(theSlider.getElementsByTagName('li').length - 3) * _this.liHeight;


					//反弹
					if (_this.curDistance[index] + _this.offsetSum > 2 * _this.liHeight) {
						_this.curDistance[index] = 2 * _this.liHeight;
						setTimeout(function () {
							_this.movePosition(theSlider, _this.curDistance[index]);
						}, 100);

					} else if (_this.curDistance[index] + _this.offsetSum < _this.oversizeBorder) {
						_this.curDistance[index] = _this.oversizeBorder;
						setTimeout(function () {
							_this.movePosition(theSlider, _this.curDistance[index]);
						}, 100);
					}

					_this.clickStatus = false;
					_this.transitionEnd(_this.getIndexArr(), _this.getValue());
					if (_this.cascade) {
						var tempPosArr = _this.getIndexArr();
						tempPosArr[index] = _this.getIndex(_this.curDistance[index]);
						_this.checkRange(index, tempPosArr);
					}
					break;

				case "mousemove":
					event.preventDefault();
					if (_this.clickStatus) {
						_this.moveY = event.clientY;
						_this.offset = _this.moveY - _this.oldMoveY;
						_this.updateCurDistance(theSlider, index);
						_this.curDistance[index] = _this.curDistance[index] + _this.offset;
						_this.movePosition(theSlider, _this.curDistance[index]);
						_this.oldMoveY = _this.moveY;
					}
					break;
			}
		},

		singleClick: function (theLi, index, sliderIndex) {
			var _this = this;
			if (_this.cascade) {
				var tempPosArr = _this.getIndexArr();
				tempPosArr[sliderIndex] = index;
				_this.checkRange(sliderIndex, tempPosArr);

			} else {
				_this.curDistance[sliderIndex] = (2 - index) * _this.liHeight;
				_this.movePosition(theLi.parentNode, _this.curDistance[sliderIndex]);
			}
		}

	};

	if (typeof exports == "object") {
		module.exports = MobileSelect;
	} else if (typeof define == "function" && define.amd) {
		define([], function () {
			return MobileSelect;
		})
	} else {
		window.MobileSelect = MobileSelect;
	}
})();
